package com.hongfan.gateway.authorization;

import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;

/**
 * 认证管理器自定义
 * 认证管理的作用就是获取传递过来的令牌，对其进行解析、验签、过期时间判定
 *
 * @author zcs
 * @since 2023/10/17
 */
@Component
public class ReactiveJdbcAuthenticationManager implements ReactiveAuthenticationManager {

    @Resource
    TokenStore jdbcTokenStore;

    @Override
    public Mono<Authentication> authenticate(Authentication authentication) {
        return Mono.justOrEmpty(authentication)
                .filter(t -> t instanceof BearerTokenAuthenticationToken)
                .cast(BearerTokenAuthenticationToken.class)
                .map(BearerTokenAuthenticationToken::getToken)
                .flatMap((accessToken -> {
                    OAuth2AccessToken oAuth2AccessToken = jdbcTokenStore.readAccessToken(accessToken);
                    System.out.println("oAuth2AccessToken is :{} " + oAuth2AccessToken);
                    if (oAuth2AccessToken == null) {
                        return Mono.error(new InvalidTokenException("无效的token"));
                    } else if (oAuth2AccessToken.isExpired()) {
                        return Mono.error(new InvalidTokenException("token已过期"));
                    }
                    OAuth2Authentication oAuth2Authentication = jdbcTokenStore.readAuthentication(accessToken);
                    if (oAuth2Authentication == null) {
                        return Mono.error(new InvalidTokenException("无效的token"));
                    } else {
                        return Mono.just(oAuth2Authentication);
                    }
                })).cast(Authentication.class);
    }
}
